package cn.linstudy.date;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 东八区日期时间工具类
 */
public class LocalDateTimeUtils {

    // 默认的日期格式
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String YYYY_MM_DD = "yyyy-MM-dd";

    public static final String YYYYMMDD = "yyyyMMdd";

    public static final String YYYY_MM = "yyyy-MM";

    public static final String YYYY_MM_DD_OF_POINT = "yyyy.MM.dd";

    public static final String MM_DD = "MM.dd";
    // 默认时区东八区
    private static final int ZONE_HOURS = 8;

    private LocalDateTimeUtils() {}

    /**
     * localDateTime转成{@link Date}
     *
     * @param localDateTime {@link Date}
     * @return {@link Date}
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneOffset.ofHours(ZONE_HOURS)).toInstant());
    }

    public static Date toDateNow() {
        return Date.from(LocalDateTime.now().atZone(ZoneOffset.ofHours(ZONE_HOURS)).toInstant());
    }

    /**
     * localDateTime转成时间戳，单位是毫秒
     *
     * @param localDateTime {@link Date}
     * @return 返回时间戳
     */
    public static long toMilliSecond(LocalDateTime localDateTime) {
        return localDateTime.toInstant(ZoneOffset.ofHours(ZONE_HOURS)).toEpochMilli();
    }

    /**
     * date转成{@link LocalDateTime}
     *
     * @param date {@link Date}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return date.toInstant().atZone(ZoneOffset.ofHours(ZONE_HOURS)).toLocalDateTime();
    }

    /**
     * 时间戳转东八区时间{@link LocalDateTime}
     *
     * @param milliSecond 时间戳
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(long milliSecond) {
        return Instant.ofEpochMilli(milliSecond).atZone(ZoneOffset.ofHours(ZONE_HOURS)).toLocalDateTime();
    }

    /**
     * localDateTime转成时间戳，单位是秒
     *
     * @param localDateTime {@link LocalDateTime}
     * @return 转成时间，单位是秒
     */
    public static long toSecond(LocalDateTime localDateTime) {
        return localDateTime.toEpochSecond(ZoneOffset.ofHours(ZONE_HOURS));
    }

    /**
     * 将localDateTime转默认格式的时间字符串
     *
     * @param localDateTime {@link LocalDateTime}
     * @return 字符串时间格式的时间
     */
    public static String format(LocalDateTime localDateTime) {
        return format(localDateTime, DEFAULT_DATE_FORMAT);
    }

    /**
     * 将localDateTime转成指定格式的时间字符串
     *
     * @param localDateTime {@link LocalDateTime}
     * @return 字符串形式的时间
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return formatter.format(localDateTime);
    }

    /**
     * 将date日期格式化成默认格式
     *
     * @param date {@link Date}
     * @return 字符串形式的时间
     */
    public static String format(Date date) {
        return format(date, DEFAULT_DATE_FORMAT);
    }

    /**
     * 将date日期格式化成指定格式
     *
     * @param date    日期
     * @param pattern 日期格式
     * @return 字符串时间格式的时间
     */
    public static String format(Date date, String pattern) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        return formatter.format(date);
    }

    /**
     * 将时间戳转成String类型的时间
     *
     * @param milliSecond 毫秒形式的时间
     * @return 字符串时间格式的时间
     */
    public static String format(long milliSecond) {
        LocalDateTime localDateTime =
            Instant.ofEpochMilli(milliSecond).atZone(ZoneOffset.ofHours(ZONE_HOURS)).toLocalDateTime();
        return format(localDateTime);
    }

    /**
     * 将时间戳转成指定格式的String类型的时间
     *
     * @param milliSecond 时间错
     * @param pattern     时间格式
     * @return 字符串形式的时间
     */
    public static String format(long milliSecond, String pattern) {
        LocalDateTime localDateTime =
            Instant.ofEpochMilli(milliSecond).atZone(ZoneOffset.ofHours(ZONE_HOURS)).toLocalDateTime();
        return format(localDateTime, pattern);
    }

    /**
     * String类型的日期转成{@link Date}
     *
     * @param date 字符串时间格式的时间
     * @return {@link Date}
     */
    public static Date toDate(String date) {
        return toDate(date, DEFAULT_DATE_FORMAT);
    }

    /**
     * String类型的日期转成{@link Date}
     *
     * @param date 字符串时间格式的时间
     * @return {@link Date}
     */
    public static Date toDate(String date, String pattern) {
        DateFormat formatter = new SimpleDateFormat(pattern);
        try {
            return formatter.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * String类型的日期date转成{@link LocalDateTime}
     *
     * @param date 字符串时间格式的时间
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(String date) {
        Date d = toDate(date, DEFAULT_DATE_FORMAT);
        return d != null ? toLocalDateTime(d) : null;
    }

    /**
     * String类型的日期date转成{@link LocalDateTime}
     *
     * @param date    字符串时间格式的时间
     * @param pattern 时间格式
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(String date, String pattern) {
        Date d = toDate(date, pattern);
        return d != null ? toLocalDateTime(d) : null;
    }

    /**
     * String 类型时间转毫秒
     *
     * @param date    字符串时间格式的时间
     * @param pattern 时间格式
     * @return 时间毫秒
     */
    public static long toMilliSecond(String date, String pattern) {
        Date d = toDate(date, pattern);
        return d == null ? -1L : d.getTime();
    }

    /**
     * String 类型时间转毫秒
     *
     * @param date 字符串时间格式的时间
     * @return 时间，单位毫秒
     */
    public static long toMilliSecond(String date) {
        Date d = toDate(date, DEFAULT_DATE_FORMAT);
        return d == null ? -1L : d.getTime();
    }

    /**
     * 获取离当前时间所在的月份最近的月份集合，
     *
     * @param num 获取的数量
     * @return 返回按日期升序排序的集合 {@link List}
     */
    public static List<String> getNearMonthListFromNow(int num) {
        List<String> dateList = new ArrayList<>();
        for (long i = num - 1; i >= 0; i--) {
            LocalDateTime localDateTime = LocalDateTime.now().minusMonths(i);
            dateList.add(LocalDateTimeUtils.format(localDateTime, LocalDateTimeUtils.YYYY_MM));
        }
        return dateList;
    }

    /**
     * 获取时间列表，排除当前日期所在的月份
     *
     * @param num 月份数量
     * @return {@link List}
     */
    public static List<String> getNearMonthListFromNowExcludeCurrentMonth(int num) {
        List<String> dateList = getNearMonthListFromNow(num);
        return dateList.subList(0, num - 1);
    }

    /**
     * 获取离当前时间所在的月份最近的月份集合，
     *
     * @param num 获取的数量
     * @return 返回按日期降序排序的集合 {@link List}
     */
    public static List<String> getNearMonthListFromNowDESC(int num) {
        List<String> dateList = new ArrayList<>();
        for (long i = 0; i <= num; i++) {
            LocalDateTime localDateTime = LocalDateTime.now().minusMonths(i);
            dateList.add(LocalDateTimeUtils.format(localDateTime, LocalDateTimeUtils.YYYY_MM));
        }
        return dateList;
    }
}
